/*
 * Copyright 2022-2027 中国信息通信研究院云计算与大数据研究所
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */ 
package com.service.impl;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.OptionalDouble;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.common.constant.TrancfgConstant;
import com.localMapper.LocalTranLogMapper;
import com.pojo.TranLogStatsDTO;
import com.pojo.Tranlog;
import com.pojo.TranlogWithOrderDTO;
import com.service.TranLogStatsService;

@Service
public class TranLogStatsServiceImpl implements TranLogStatsService {

    @Autowired
    private LocalTranLogMapper localTranLogMapper;

    @Override
    public Map<String, List<Integer>> getTmcostList(String process_id) {
        Map<String, List<Integer>> map = new HashMap<>();
        map.put(TrancfgConstant.TRANCFG_ACCOUNTS_TRANSFER, getTmcostListValue(TrancfgConstant.TRANCFG_ACCOUNTS_TRANSFER, process_id));
        map.put(TrancfgConstant.TRANCFG_ACCOUNTS_QUERY, getTmcostListValue(TrancfgConstant.TRANCFG_ACCOUNTS_QUERY, process_id));
        map.put(TrancfgConstant.TRANCFG_ACCOUNTS_SALARY, getTmcostListValue(TrancfgConstant.TRANCFG_ACCOUNTS_SALARY, process_id));
        map.put(TrancfgConstant.TRANCFG_ACCOUNTS_DEPOSIT, getTmcostListValue(TrancfgConstant.TRANCFG_ACCOUNTS_DEPOSIT, process_id));
        map.put(TrancfgConstant.TRANCFG_ACCOUNTS_WITHDRAW, getTmcostListValue(TrancfgConstant.TRANCFG_ACCOUNTS_WITHDRAW, process_id));
        return map;
    }

    private List<Integer> getTmcostListValue(String trancfgid, String process_id) {
        List<Integer> list = new ArrayList<>();
        List<TranlogWithOrderDTO> orderDTOList;
        Tranlog param = new Tranlog();
        param.setTranlog_trancfgid(trancfgid);
        param.setTranlog_fld1(process_id);
        Integer allCountById = localTranLogMapper.countTranlog(param).intValue();
        int times = allCountById / 1000;
        if (allCountById <= 1000) {
            list = localTranLogMapper.findTmcostByTrancfgid(trancfgid, process_id);
        } else if (allCountById < 10000) {
            list = localTranLogMapper.findTmcostByTrancfgid(trancfgid, process_id);
            List<Integer> filtedList = new ArrayList<>();
            for (int i = 0; i < list.size(); i++) {
            	if((i + times - 1)<list.size()) {
                    filtedList.add(list.get(i + times - 1));
            	}
            }
            list = filtedList.subList(0, 999);
        } else {
            int index = 10 - (String.valueOf(times).length() - 2);
            long subStrTime = (long) (times / 10);
            orderDTOList = localTranLogMapper.findTmcostWithFilterByTrancfgid(trancfgid, index+3, subStrTime, process_id);
            for (int i = 0; i < 10; i++) {
                if (orderDTOList.size() <= 1000) {
                    orderDTOList.addAll(localTranLogMapper.findTmcostWithFilterByTrancfgid(trancfgid, index+3, subStrTime++, process_id));
                } else {
                    List<TranlogWithOrderDTO> collect = orderDTOList.stream().sorted(Comparator.comparing(TranlogWithOrderDTO::getUnixStrTime)).collect(Collectors.toList());
                    int timesForOrderedList = collect.size() / 1000;
                    for (int j = 0; j < collect.size(); j++) {
                    	if((j + timesForOrderedList - 1)<collect.size()) {
                            list.add(collect.get(j + timesForOrderedList - 1).getTmcost());
                    	}
                    }
                    list = list.subList(0, 999);
                }
            }
        }
        return list;
    }

    @Override
    public Map<String, List<TranLogStatsDTO>> getTmcostCount(String process_id) {
        Map<String, List<TranLogStatsDTO>> map = new HashMap<>();
        map.put(TrancfgConstant.TRANCFG_ACCOUNTS_TRANSFER, getTimecostCount(localTranLogMapper.findTmcostCountByTrancfgid(TrancfgConstant.TRANCFG_ACCOUNTS_TRANSFER, process_id)));
        map.put(TrancfgConstant.TRANCFG_ACCOUNTS_QUERY, getTimecostCount(localTranLogMapper.findTmcostCountByTrancfgid(TrancfgConstant.TRANCFG_ACCOUNTS_QUERY, process_id)));
        map.put(TrancfgConstant.TRANCFG_ACCOUNTS_SALARY, getTimecostCount(localTranLogMapper.findTmcostCountByTrancfgid(TrancfgConstant.TRANCFG_ACCOUNTS_SALARY, process_id)));
        map.put(TrancfgConstant.TRANCFG_ACCOUNTS_DEPOSIT, getTimecostCount(localTranLogMapper.findTmcostCountByTrancfgid(TrancfgConstant.TRANCFG_ACCOUNTS_DEPOSIT, process_id)));
        map.put(TrancfgConstant.TRANCFG_ACCOUNTS_WITHDRAW, getTimecostCount(localTranLogMapper.findTmcostCountByTrancfgid(TrancfgConstant.TRANCFG_ACCOUNTS_WITHDRAW, process_id)));
        return map;
    }

    private List<TranLogStatsDTO> getTimecostCount(List<TranLogStatsDTO> list) {
        int columnNum = 10;
        OptionalDouble average = list.stream().mapToInt(TranLogStatsDTO::getTmcost).average();
        if (!average.isPresent()) {
            list = new ArrayList<>();
            list.add(new TranLogStatsDTO(0, 0l));
            return list;
        }
        Integer max = list.stream().mapToInt(TranLogStatsDTO::getTmcost).max().getAsInt();
        int space = (int) average.getAsDouble() * 2 / columnNum;
        return groupAndCountList(list, space, max, columnNum);
    }

    private List<TranLogStatsDTO> groupAndCountList(List<TranLogStatsDTO> list, int space, int max, int columnNum) {
        List<TranLogStatsDTO> tranLogStatsDTOList = new ArrayList<>();
        for (int i = 1; i < columnNum + 1; i++) {
            if (i * space < max) {
                if (i < columnNum) {
                    int finalI = i;
                    int finalI1 = i;
                    long sum = list.stream().filter(tranLogStatsDTO -> ((finalI - 1) * space <= tranLogStatsDTO.getTmcost()) && (tranLogStatsDTO.getTmcost() < (finalI1 * space))).mapToLong(TranLogStatsDTO::getCountNum).sum();
                    tranLogStatsDTOList.add(new TranLogStatsDTO(i * space, sum));
                } else {
                    int finalI3 = i;
                    long sum = list.stream().filter(tranLogStatsDTO -> (finalI3 * space <= tranLogStatsDTO.getTmcost()) && (tranLogStatsDTO.getTmcost() < max)).mapToLong(TranLogStatsDTO::getCountNum).sum();
                    tranLogStatsDTOList.add(new TranLogStatsDTO(max, sum));
                    break;
                }
            } else {
                int finalI2 = i;
                long sum = list.stream().filter(tranLogStatsDTO -> ((finalI2 - 1) * space <= tranLogStatsDTO.getTmcost()) && (tranLogStatsDTO.getTmcost() < max)).mapToLong(TranLogStatsDTO::getCountNum).sum();
                tranLogStatsDTOList.add(new TranLogStatsDTO(max, sum));
            }
        }
        return tranLogStatsDTOList;
    }
}
